package net.bgraham.collectionbatcher;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import junit.framework.TestCase;
import net.bgraham.collectionbatcher.ArrayListBatcher;
import net.bgraham.collectionbatcher.ConflatingBatcher;
import net.bgraham.collectionbatcher.IBatchListener;
import net.bgraham.collectionbatcher.Log;
import net.bgraham.collectionbatcher.Util.CellInfo;

import org.junit.Before;
import org.junit.Test;

public class ArrayListBatcherTestForCellInfos extends TestCase
{
	private static long maxTimeToWaitBetweenBatches = 900;
	private static long maxTimeToWaitBetweenUpdates = 100;
	
	static long count = 0;
	static long batches = 0;
	static long fullTimeoutCount = 0;
	static long earlyTimeoutCount = 0;
	
    @Override
	@Before
    public void setUp()
    {
    	count = 0;
    	batches = 0;
    	fullTimeoutCount = 0;
    	earlyTimeoutCount = 0;
    }

	@Test
	public static void testBatcherWithOneThousandCellInfosAndDelaysBetweenAddsShouldHaveNoLosses()
	{
		count = 0;
		
		Log.log("testBatcherWithOneThousandCellInfosAndDelaysBetweenAddsShouldHaveNoLosses()");
		final List<CellInfo> receivedList = new ArrayList<CellInfo>();
		List<CellInfo> sentList = new ArrayList<CellInfo>();
		for (int i=0; i<1000; i++)
		{
			sentList.add(new CellInfo(i, i));
		}
		
		ArrayListBatcher<CellInfo> batcher = new ArrayListBatcher<CellInfo>(
				new IBatchListener<CellInfo>()
				{
					public void batchCollected(Collection<CellInfo> batch, boolean fullTimeoutHit)
					{
						receivedList.addAll(batch);
						if (++count % 25 == 0)
						{
							Log.log("size = " + receivedList.size());
							Util.printBatchStats(batches, fullTimeoutCount, earlyTimeoutCount);
						}
						batches++;
						if (fullTimeoutHit)
						{
							fullTimeoutCount++;
						}
						else
						{
							earlyTimeoutCount++;
						}
					}
				},
				maxTimeToWaitBetweenBatches, maxTimeToWaitBetweenUpdates
				);

		for (CellInfo val : sentList)
		{
			batcher.add(val);
			if (val.getRow() % 100 == 0)
			{
				Util.doSleep((long)(Math.random() * 150));
			}
		}
		// pause to let batcher send any remaining data and shut down nicely
		Util.doSleep(1000);
		batcher.exit();
		
		Util.printBatchStats(batches, fullTimeoutCount, earlyTimeoutCount);
		Util.printResults(sentList.size(), receivedList.size());
		assertTrue("Received values are different than sent values", sentList.equals(receivedList));
		Log.log("\n");
	}

	@Test
	public static void testConflatingBatcherWithOneThousandCellInfosRepeatedFiveTimesWithinOneBatchShouldOnlyReturnOneThousandCellInfos()
	{
		count = 0;
		
		Log.log("testConflatingBatcherWithOneThousandCellInfosRepeatedFiveTimesWithinOneBatchShouldOnlyReturnOneThousandCellInfos()");
		final List<CellInfo> receivedList = new ArrayList<CellInfo>();
		List<CellInfo> sentList = new ArrayList<CellInfo>();
		for (int i=0; i<1000; i++)
		{
			sentList.add(new CellInfo(i, i));
		}
		
		ConflatingBatcher<CellInfo> batcher = new ConflatingBatcher<CellInfo>(
				new IBatchListener<CellInfo>()
				{
					public void batchCollected(Collection<CellInfo> batch, boolean fullTimeoutHit)
					{
						receivedList.addAll(batch);
						if (++count % 25 == 0)
						{
							Log.log("size = " + receivedList.size());
							Util.printBatchStats(batches, fullTimeoutCount, earlyTimeoutCount);
						}
						batches++;
						if (fullTimeoutHit)
						{
							fullTimeoutCount++;
						}
						else
						{
							earlyTimeoutCount++;
						}
					}
				},
				maxTimeToWaitBetweenBatches, maxTimeToWaitBetweenUpdates
				);

		for (int i=0; i<5; i++)
		{
			for (CellInfo val : sentList)
			{
				batcher.add(val);
			}
		}
		
		// pause to let batcher send any remaining data and shut down nicely
		Util.doSleep(1000);
		batcher.exit();
		
		Collections.sort(receivedList);

		Util.printBatchStats(batches, fullTimeoutCount, earlyTimeoutCount);
		Util.printResults(sentList.size(), receivedList.size());
		assertTrue("Received values are different than sent values", sentList.equals(receivedList));
		Log.log("\n");
	}
}
